#pragma once

#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include "../util/config.hh"
#include "../util/dbconn.hh"
#include "../poco/community-post.hh"

namespace WordMemory
{
    class CommunityRepository
    {
    public:
        static CommunityRepository& instance()
        {
            static CommunityRepository inst;
            return inst;
        }

    public:
        // 获取单个帖子详情
        CommunityPost getPostById(int post_id) {
            ConnectionGuard conn;
            try {
                std::unique_ptr<sql::PreparedStatement> pstmt(
                    conn.get()->prepareStatement(
                        "SELECT id, user_id, title, content, likes_count, shares_count, created_at, updated_at, "
                        "(SELECT username FROM users WHERE id = community_posts.user_id) as author_username " // 获取作者名
                        "FROM community_posts WHERE id = ?"));
                pstmt->setInt(1, post_id);
                std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
                if (res->next()) {
                    CommunityPost post( // 确保CommunityPost有构造函数或方法处理新字段
                        res->getInt("id"),
                        res->getInt("user_id"),
                        res->getString("title"),
                        res->getString("content"),
                        res->getString("created_at"),
                        res->getString("updated_at")
                    );
                    post.likes_count = res->getInt("likes_count");
                    post.shares_count = res->getInt("shares_count");
                    post.author_username = res->getString("author_username"); // 假设CommunityPost POCO增加了此字段
                    return post;
                }
                throw RepositoryExcept("Post not found with id: " + std::to_string(post_id));
            }
            catch (const sql::SQLException& e) {
                spdlog::error("Failed to get post by id {}: {}", post_id, e.what());
                throw RepositoryExcept("Failed to get post: " + std::string(e.what()));
            }
        }

        // 点赞帖子 (增加计数并记录点赞用户)
        bool likePost(int post_id, int user_id) {
            ConnectionGuard conn;
            try {
                conn.get()->setAutoCommit(false); // Start transaction

                // 1. 检查是否已点赞
                std::unique_ptr<sql::PreparedStatement> check_stmt(
                    conn.get()->prepareStatement("SELECT id FROM community_post_likes WHERE post_id = ? AND user_id = ?"));
                check_stmt->setInt(1, post_id);
                check_stmt->setInt(2, user_id);
                std::unique_ptr<sql::ResultSet> res_check(check_stmt->executeQuery());

                if (res_check->next()) { // 已点赞，则执行取消点赞
                    std::unique_ptr<sql::PreparedStatement> unlike_stmt(
                        conn.get()->prepareStatement("DELETE FROM community_post_likes WHERE post_id = ? AND user_id = ?"));
                    unlike_stmt->setInt(1, post_id);
                    unlike_stmt->setInt(2, user_id);
                    unlike_stmt->executeUpdate();

                    std::unique_ptr<sql::PreparedStatement> dec_stmt(
                        conn.get()->prepareStatement("UPDATE community_posts SET likes_count = GREATEST(0, likes_count - 1) WHERE id = ?"));
                    dec_stmt->setInt(1, post_id);
                    dec_stmt->executeUpdate();

                    conn.get()->commit();
                    conn.get()->setAutoCommit(true);
                    spdlog::info("User {} unliked post {}", user_id, post_id);
                    return false; // 表示执行了取消点赞
                }
                else { // 未点赞，则执行点赞
                    std::unique_ptr<sql::PreparedStatement> like_stmt(
                        conn.get()->prepareStatement("INSERT INTO community_post_likes (post_id, user_id) VALUES (?, ?)"));
                    like_stmt->setInt(1, post_id);
                    like_stmt->setInt(2, user_id);
                    like_stmt->executeUpdate();

                    std::unique_ptr<sql::PreparedStatement> inc_stmt(
                        conn.get()->prepareStatement("UPDATE community_posts SET likes_count = likes_count + 1 WHERE id = ?"));
                    inc_stmt->setInt(1, post_id);
                    inc_stmt->executeUpdate();

                    conn.get()->commit();
                    conn.get()->setAutoCommit(true);
                    spdlog::info("User {} liked post {}", user_id, post_id);
                    return true; // 表示执行了点赞
                }
            }
            catch (const sql::SQLException& e) {
                try { if (conn.get()) conn.get()->rollback(); }
                catch (const sql::SQLException& rbEx) { spdlog::error("Rollback failed: {}", rbEx.what()); }
                try { if (conn.get()) conn.get()->setAutoCommit(true); }
                catch (const sql::SQLException& acEx) { spdlog::error("SetAutoCommit(true) failed: {}", acEx.what()); }
                spdlog::error("Failed to like/unlike post {}: {}", post_id, e.what());
                throw RepositoryExcept("Database error during like/unlike operation: " + std::string(e.what()));
            }
        }

        // 检查用户是否已点赞
        bool isPostLikedByUser(int post_id, int user_id) {
            ConnectionGuard conn;
            try {
                std::unique_ptr<sql::PreparedStatement> pstmt(
                    conn.get()->prepareStatement("SELECT 1 FROM community_post_likes WHERE post_id = ? AND user_id = ? LIMIT 1"));
                pstmt->setInt(1, post_id);
                pstmt->setInt(2, user_id);
                std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
                return res->next();
            }
            catch (const sql::SQLException& e) {
                spdlog::error("Failed to check if post {} is liked by user {}: {}", post_id, user_id, e.what());
                return false; // Or throw
            }
        }

        // 增加分享计数
        void incrementShareCount(int post_id) {
            ConnectionGuard conn;
            try {
                std::unique_ptr<sql::PreparedStatement> pstmt(
                    conn.get()->prepareStatement("UPDATE community_posts SET shares_count = shares_count + 1 WHERE id = ?"));
                pstmt->setInt(1, post_id);
                pstmt->executeUpdate();
                spdlog::info("Incremented share count for post {}", post_id);
            }
            catch (const sql::SQLException& e) {
                spdlog::error("Failed to increment share count for post {}: {}", post_id, e.what());
                // Not throwing an exception here as it's less critical than like, client might proceed with OS share
            }
        }

        // 修改 getCommunityPosts 以包含作者名和点赞分享数
        std::vector<CommunityPost> getCommunityPosts(int current_user_id = 0) // Optional current_user_id for is_liked status
        {
            ConnectionGuard conn;
            try
            {
                // Query needs to join with users table for author name and potentially likes table for current user's like status
                std::string query =
                    "SELECT cp.id, cp.user_id, u.username as author_username, cp.title, cp.content, "
                    "cp.likes_count, cp.shares_count, cp.created_at, cp.updated_at ";
                if (current_user_id > 0) {
                    query += ", EXISTS(SELECT 1 FROM community_post_likes cpl WHERE cpl.post_id = cp.id AND cpl.user_id = ?) as is_liked_by_current_user ";
                }
                query += "FROM community_posts cp JOIN users u ON cp.user_id = u.id ORDER BY cp.created_at DESC";

                std::unique_ptr<sql::PreparedStatement> pstmt(conn.get()->prepareStatement(query));
                if (current_user_id > 0) {
                    pstmt->setInt(1, current_user_id);
                }
                std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());

                std::vector<CommunityPost> posts;
                while (res->next())
                {
                    CommunityPost post(
                        res->getInt("id"),
                        res->getInt("user_id"),
                        res->getString("title"),
                        res->getString("content"),
                        res->getString("created_at"),
                        res->getString("updated_at")
                    );
                    post.author_username = res->getString("author_username");
                    post.likes_count = res->getInt("likes_count");
                    post.shares_count = res->getInt("shares_count");
                    if (current_user_id > 0) {
                        post.is_liked_by_current_user = res->getBoolean("is_liked_by_current_user");
                    }
                    posts.push_back(post);
                }
                return posts;
            }
            catch (const sql::SQLException& e)
            {
                spdlog::error("Failed to get community posts (with details): {}", e.what());
                throw RepositoryExcept("Failed to get community posts: " + std::string(e.what()));
            }
        }

    private:
        CommunityRepository() = default;
        CommunityRepository(const CommunityRepository&) = delete;
        CommunityRepository& operator=(const CommunityRepository&) = delete;
    };
}